﻿using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using RG.Common.Configuration;
using RG.Common.WPF.Commands;
using RG.Common.WPF.Settings;
using Microsoft.Practices.Unity;
using RG.Common;
using RG.Common.Configuration;

namespace RG.Common.WPF.Workplaces
{

    [SupportDataBinding]
    public class MultiFrameWorkplaceVM : BaseFrameWorkplace
    {
        public ICommand HideAlarmCmd { get; set; }
        public ICommand ShowItemCmd { get; set; }

        public object MessageHintView { get; set; }
        public bool HasMessage { get; set; }

        [InjectionConstructor]
        public MultiFrameWorkplaceVM(IUnityContainer parentCfg, IWorkplace parentWorkplace, IUserSettings userSettings)
            : base(parentCfg,parentWorkplace)
        {
            
            var cfg = Cfg.Resolve<MultiWorkplaceConfig>();
            var rootItem = userSettings.UserFrames();
            Root = cfg.ResolveGroup(null, (FrameGroup)rootItem);
            ShowItemCmd = new DelegateCommand<FrameDescVM>(DoShowItem);
            HideAlarmCmd = new DelegateCommand(DoHideAlarms, ()=> HasMessage);
        }

        private void DoHideAlarms()
        {
            HasMessage = false;
            //todo grigor надобно еще избавиться от предыдущего контрола
        }

        private void DoShowItem(FrameDescVM itm)
        {
            if (itm.Item is FrameSingle) ShowNew(itm);
            if (itm.Item is FrameGroup) itm.IsExpanded = !itm.IsExpanded;
            itm.IsSelected = false; // если вдруг умудрились попасть в итем, а не в его темплейт - убираем выделение
        }

        public FrameDescVM Root { get; set; }

        public FrameDescVM Selected { get { return (FrameDescVM)Root.SelectedItem; } }

        private int lastHistoryIndex;

        public FrameTab SelectedTab
        {
            get { return selectedTab; }
            set
            {
                selectedTab = value;
                if (selectedTab != null) selectedTab.HistoryIndex = ++lastHistoryIndex;
                if (selectedTab != null) UpdateSettingsArray(selectedTab.SettingsIndex);
            }
        }
       
        public void ShowNew(FrameDescVM fiVM)
        {
            FrameTab tab;
            if (fiVM.Item is SingleTabFrame && FindTabForVM(fiVM, out tab))
                Show(fiVM);
            else if (fiVM.Item is FrameSingle)
            {
                var typeofWorkplace = typeof (MultiFrameWorkplaceVM);
                var methodInfo = typeofWorkplace.GetMethod("CreateTab");
                var fs = (FrameSingle) fiVM.Item;
                var genericArguments = new[] {fs.Type};
                var genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
                var presenter = Cfg.Resolve(fs.Type);
                genericMethodInfo.Invoke(this, new[] {presenter, fiVM});
                if (presenter is IOnShow)
                    (presenter as IOnShow).OnShow();
            }
        }

        public void CreateTab<TPresenter>(TPresenter presenter, FrameDescVM fiVM)
        {
            var v = Cfg.Resolve<IView<TPresenter>>();
            v.Presenter = presenter;

            var config = (fiVM != null) ? fiVM.Config : new FrameConfigSettings {Id = presenter.GetType().GUID};

            var tab = new FrameTab
                          {
                              Presenter = presenter,
                              View = v,
                              FrameDescVM = fiVM,
                              Config = config,
                              PresenterSettings = Cfg.Resolve<IApplicationSettings>(),
                              ViewSettings = new WpfSettings()
                          };

            tab.OnFrameTabSelectted += DoSelect;
            
            tab.PresenterSettings.Bind(tab.Config.Id.ToString(), presenter);
            tab.PresenterSettings.Load();
            
            tab.ViewSettings.Bind(tab.Config.Id.ToString(), v);
            tab.ViewSettings.Load();

            Tabs.Add(tab);
            SelectedTab = tab;

            if (presenter is IFrameForMultiWorkplace)
            {
                var frame = (IFrameForMultiWorkplace)presenter;
                if (fiVM != null)
                    frame.Name = fiVM.Name;
            }
        }

        private void DoSelect(FrameTab item)
        {
            if (item != null)
            SelectedTab = item;
        }

        public bool CloseTab(object presenter)
        {
            FrameTab tab;
            if (!FindTabFor(presenter, out tab)) return false;

            if (tab.Config.FilterSaveType == SaveType.SaveTypeOnClose)
                tab.PresenterSettings.Save();

            if (tab.Config.ColumnsSaveType == SaveType.SaveTypeOnClose)
                tab.ViewSettings.Save();

            if (Tabs.Count > 1)
            {
                var idx = Tabs.Where(t => t != tab).Max(x => x.HistoryIndex);
                SelectedTab = Tabs.FirstOrDefault(x => x.HistoryIndex == idx);
            }

            Tabs.Remove(tab);
            return true;
        }
       
        public bool FindTabFor(object presenter, out FrameTab tab)
        {
            tab = null;
            foreach (var t in Tabs)
                if (t.Presenter == presenter)
                {
                    tab = t;
                    break;
                }
            return (tab != null);
        }

        public bool FindTabForVM(FrameDescVM fiVM, out FrameTab tab)
        {
            tab = null;
            foreach (var t in Tabs)
                if (t.FrameDescVM == fiVM)
                {
                    tab = t;
                    break;
                }
            return (tab != null);
        }

        public void Show(FrameDescVM fiVM)
        {
            FrameTab tab;
            if (FindTabForVM(fiVM, out tab))
                SelectedTab = tab;
            else
            {
                ShowNew(fiVM);
            }
        }

        private static FrameTab FindTab(object presenter, IEnumerable<FrameTab> ss)
        {
            foreach (var t in ss)
                if (t.Presenter == presenter)
                    return t;
            return null;
        }

        #region Implementation of IWorkplace
        
        public override void Show<T>(T presenter)
        {
            FrameTab tab;
            if (FindTabFor(presenter, out tab))
                SelectedTab = tab;
            else
                CreateTab(presenter, null);
        }

        public override void Close(object presenter)
        {
            FrameTab tab;
            if (!FindTabFor(presenter, out tab)) return;
            if (!((IFrameForMultiWorkplace) presenter).CanClose) return;
            CloseTab(presenter);
        }

        public override void ShowAlarm<TalarmManager>(TalarmManager frame, int id)
        {
            if (!HasMessage)
            {
                var v = Cfg.Resolve<IView<TalarmManager>>();
                v.Presenter = frame;
                ((IAlarmFrame) frame).CanShowAlarm -= ShowAlamPanel;
                ((IAlarmFrame)frame).CanShowAlarm += ShowAlamPanel;
                ((IAlarmFrame) frame).Init(id);
                MessageHintView = v;
            }
            else
            {
                var alarmFrame = ((IAlarmFrame) ((IView<TalarmManager>) MessageHintView).Presenter);
                if (alarmFrame.IsFree) alarmFrame.Refresh(id);
            }
        }

        public void ShowAlamPanel()
        {
            HasMessage = true;
        }

        public override void CloseAlarm()
        {
            HasMessage = false;
        }

        #endregion

        public override bool CanClose
        {
            get
            {
                while (Tabs.Count > 0)
                {
                    var tab = Tabs[0];
                    if (tab.Presenter is IWorkplaceObject)
                    {
                        var obj = (IWorkplaceObject) tab.Presenter;
                        SelectedTab = tab;
                        if (!obj.CanClose)
                            return false;
                    }
                    CloseTab(Tabs[0].Presenter);
                }
                presenterSettings.Save();
                return true;
            }
        }
    }
}

